#include "mainwindow.h"
#include "serialport/qscom.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QFile>
#include <QFileInfo>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QMessageBox>
#include <QPlainTextEdit>
#include <USB_monitor.h>
#include <unistd.h>
#include <QTimer>
#include <QScrollBar>
#include <QDateTime>
#include <settingswindow.h>

#ifdef Q_OS_WIN
#include <Windows.h>
#include <dbt.h>
#elif defined(Q_OS_LINUX)

#endif


int uiToJsonStr(const Ui::MainWindow &ui, std::string &str);
int jsonStrToUi(const std::string &str, Ui::MainWindow &ui);

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
    , qsc()
    , settings("qscom", "qscom")
{
    ui->setupUi(this);

    connect(&qsc, &qscoms::sigSpDataReceive, this, &MainWindow::slotSpDataReceive);
    readUiConfig();
    restoreUiWindow();
    uiInit();
    ui->textEdit_sendBuf->installEventFilter(this);

#ifdef LINUX_USB_MONITOR_MOD
    /* USB Monitor thread*/
    usbMonitor = new QThread(this);
    usbmThread = new USBMonitor(this);
    usbmThread->moveToThread(usbMonitor);
    timer = new QTimer(this);
    connect(this, &MainWindow::sigUSBMonitorExec, usbmThread, &USBMonitor::slotUSBMonitorExec);
    connect(usbMonitor, &QThread::finished, usbmThread, &QObject::deleteLater);
    connect(usbmThread, &USBMonitor::sigUSBDetected, this, &MainWindow::slotUSBDetected);
    usbMonitor->start();
    qDebug() << "Starting a new thread for USB Monitor";
    emit sigUSBMonitorExec();
#endif
}

MainWindow::~MainWindow()
{
#ifdef LINUX_USB_MONITOR_MOD
    usbmThread->stop();
    usbMonitor->quit();
    usbMonitor->wait();
#endif
    delete ui;
}

void MainWindow::slotUSBRefresh()
{
    on_refresh_triggered();
}

void MainWindow::slotUSBDetected(QString info)
{
#ifdef LINUX_USB_MONITOR_MOD
    if (info.contains("ttyUSB") && info.contains("bind") && !info.contains("unbind")) {
        QTimer::singleShot(1000, this, SLOT(slotUSBRefresh()));
    } else if (info.contains("ttyACM") && info.contains("add")) {
        QTimer::singleShot(1000, this, SLOT(slotUSBRefresh()));
    } else if (info.contains("remove") && ( info.contains("ttyUSB") || info.contains("ttyACM")) ) {
        on_refresh_triggered();
    }
#else

#endif
}

void MainWindow::dataRecWidgetAppend(int index, const QString & data)
{
    QPlainTextEdit *pte = (QPlainTextEdit *)ui->tabWidget->widget(index);
    QScrollBar *scrollbar = pte->verticalScrollBar();
    int pos = scrollbar->sliderPosition();
    int max = scrollbar->maximum();
    pte->moveCursor(QTextCursor::End);
    pte->insertPlainText(data);
    if (pos == max) {
        scrollbar->setSliderPosition(scrollbar->maximum());
    } else {
        scrollbar->setSliderPosition(pos);
    }
}

/**
 * @brief MainWindow::slotSpDataReceive
 * @details 已知问题：当\r\n被分开接受时，界面会显示一个空白行
 * @param name
 * @param data
 */
void MainWindow::slotSpDataReceive(QString name, QString data)
{
    if (!ui->radioButton_rec->isChecked()) {
        qInfo() << "data receive is closed";
        return ;
    }

    /* 检测数据发送者的串口是否打开或者存在 */
    int tabSize = ui->tabWidget->count();
    int index = -1;
    for (int i = 0; i < tabSize; i++) {
        PageInfo &pi = pInfo[i];
        if (name == pi.name && pi.open == true) {
            index = i;
            break;
        }
    }
    if (index < 0) {
        return ;
    }

    if (ui->checkBox_showTime->isChecked()) {
        QDateTime timestamp = QDateTime::currentDateTime();
        data = timestamp.toString("[yyyy-MM-dd hh:mm:ss]>> ") + data;
        /* 当启用时间戳时，对没有换行符的数据进行换行显示 */
        int pos = data.length();
        if (data.at(pos - 1) == '\r') {
            if (data.at(pos - 2) != '\n') {
                data += "\n";
            } else {
                data.remove(pos - 1, 1);
            }
        } else if (data.at(pos - 1) != '\n') {
            data += "\n";
        }
    }

    PageInfo * pi = getPageInfo(name);
    pi->fLog->logSave(data);

    dataRecWidgetAppend(index, data);
//    qDebug() << name << " serialport receive: " << data;
}

/**
 * @brief MainWindow::uiInit
 * @details plainTextEdit 会把"\r"输出为换行
 */
void MainWindow::uiInit()
{
    statusBarInit();
    on_refresh_triggered();

    this->baudRate << qscom::Baud115200 << qscom::Baud57600 << qscom::Baud38400 << qscom::Baud19200 << qscom::Baud9600
                   << qscom::Baud4800 << qscom::Baud2400 << qscom::Baud1200;
    QStringList br;
    br << "115200"
       << "57600"
       << "38400"
       << "19200"
       << "9600"
       << "4800"
       << "2400"
       << "1200";
    ui->comboBox_baudRate->addItems(br);

    this->dataBits << qscom::Data8 << qscom::Data7 << qscom::Data6 << qscom::Data5;
    QStringList db;
    db << "8"
       << "7"
       << "6"
       << "5";
    ui->comboBox_dataBits->addItems(db);

    this->parity << qscom::NoParity << qscom::OddParity << qscom::EvenParity << qscom::SpaceParity << qscom::MarkParity;
    QStringList pa;
    pa << tr("无校验") << tr("奇校验") << tr("偶校验") << tr("空校验") << tr("标记校验");
    ui->comboBox_parity->addItems(pa);

    this->stopBits << qscom::OneStop << qscom::OneAndHalfStop << qscom::TwoStop;
    QStringList stb;
    stb << "1"
        << "1.5"
        << "2";
    ui->comboBox_stopBits->addItems(stb);

    this->endChar << "\n"
                  << "\r"
                  << ""
                  << "NULL"
                  << "\r\n"
                  << "\n\r";
    QStringList endc;
    endc << "\\n"
         << "\\r"
         << "\\0"
         << "NULL"
         << "\\r\\n"
         << "\\n\\r";
    ui->comboBox_endChar->addItems(endc);

    this->flowCtrl << qscom::NoFlowControl << qscom::SoftwareControl << qscom::HardwareControl;
    QStringList fwctrl;
    fwctrl << tr("无") << tr("软件") << tr("硬件");
    ui->comboBox_flowCtrl->addItems(fwctrl);

    newTab();
    ui->tabWidget->setTabsClosable(false);

    int tabSize   = ui->tabWidget->count();
    int pInfoSize = pInfo.size();
    int diff;
    qDebug() << "tabSize: " << tabSize << ", pInfoSize: " << pInfoSize;
    if (tabSize < pInfoSize) {
        diff = pInfoSize - tabSize;
        for (int i = 0; i < diff; i++) {
            newTab();
        }
    } else if (tabSize > pInfoSize) {
        for (int i = pInfoSize; i < tabSize; i++) {
            qDebug() << "add Page info into pInfo";
            PageInfo pi;
            pInfo << pi;
            getPageInfo(i);
        }
    }
    qDebug() << "pInfo size: " << pInfo.size();

    setPageInfo(ui->tabWidget->currentIndex());
    ui->show_Tool_Bar->trigger();
    ui->showSettingsWin->trigger();

    /*设置等宽字体*/
    ui->textEdit_sendBuf->setFont(QFont(tr("Consolas")));

    ui->action_logToFile->setChecked(globalSettings.log.enableToFile);
}

void MainWindow::setPageInfo(int index)
{
    qDebug() << "set page info index: " << index;
    int pInfoSize = pInfo.size();
    if (pInfoSize - 1 < index) {
        qInfo() << "not found tab to set page info";
        return;
    }

    PageInfo &pi = pInfo[index];
    ui->comboBox_baudRate->setCurrentIndex(baudRate.indexOf(pi.pc.baudRate));
    ui->comboBox_dataBits->setCurrentIndex(dataBits.indexOf(pi.pc.dataBits));
    ui->comboBox_flowCtrl->setCurrentIndex(flowCtrl.indexOf(pi.pc.flowCtrl));
    ui->comboBox_parity->setCurrentIndex(parity.indexOf(pi.pc.parity));
    ui->comboBox_stopBits->setCurrentIndex(stopBits.indexOf(pi.pc.stopBits));

    ui->comboBox_endChar->setCurrentIndex(endChar.indexOf(pi.endChar));
    ui->checkBox_echo->setChecked(pi.echo);
    ui->checkBox_showTime->setChecked(pi.showTimestamp);
    ui->radioButton_rec->setChecked(!pi.recStop);
    int indexPort = getPortIndex(pi.name);
    if (indexPort < 0) {
        ui->comboBox_port->setCurrentIndex(0);
    } else {
        ui->comboBox_port->setCurrentIndex(indexPort);
    }

    ui->openPort->setChecked(pi.open);
    ui->noReceive->setChecked(pi.recStop);
    ui->recCached->setChecked(pi.recCached);
    ui->linuxMode->setChecked(pi.linuxMode);
    emit ui->linuxMode->triggered(pi.linuxMode);
    clockUi(pi.open);

    /* records of send */
    int itemCount = pi.sendRecords.size();
    ui->listWidget_sendRecords->clear();
    for (int i = 0; i < itemCount; i++) {
        ui->listWidget_sendRecords->addItem(pi.sendRecords[i]);
    }
    isSendRecordSelect = false;
}

void MainWindow::getPageInfo(int index)
{
    qDebug() << "get page info index: " << index;
    int pInfoSize = pInfo.size();
    if (index + 1 > pInfoSize || ui->tabWidget->count() <= 0) {
        qInfo() << "not found index for saving tab page info, pInfoSize: " << pInfoSize;
        return;
    }

    PageInfo &pi     = pInfo[index];
    pi.name          = getPortName(ui->comboBox_port->currentIndex());
    pi.endChar       = endChar[ui->comboBox_endChar->currentIndex()];
    pi.echo          = ui->checkBox_echo->isChecked();
    pi.recStop       = !ui->radioButton_rec->isChecked();
    pi.showTimestamp = ui->checkBox_showTime->isChecked();
    pi.linuxMode     = ui->linuxMode->isChecked();
    pi.recCached     = ui->recCached->isChecked();
    pi.pc.baudRate   = baudRate[ui->comboBox_baudRate->currentIndex()];
    pi.pc.dataBits   = dataBits[ui->comboBox_dataBits->currentIndex()];
    pi.pc.flowCtrl   = flowCtrl[ui->comboBox_flowCtrl->currentIndex()];
    pi.pc.parity     = parity[ui->comboBox_parity->currentIndex()];
    pi.pc.stopBits   = stopBits[ui->comboBox_stopBits->currentIndex()];

    int itemCount = ui->listWidget_sendRecords->count();
    pi.sendRecords.clear();
    for (int i = 0; i < itemCount; i++) {
        pi.sendRecords << ui->listWidget_sendRecords->item(i)->text();
    }
}

int MainWindow::newTab()
{
    QPlainTextEdit *pte = new QPlainTextEdit(ui->tabWidget->currentWidget());
    pte->setFont(QFont(tr("Consolas")));
    pte->setReadOnly(true);
    int index = ui->tabWidget->addTab(pte, "new");
    if (ui->tabWidget->count() >= 1) {
        ui->tabWidget->setTabsClosable(true);
    }
    ui->tabWidget->setTabIcon(index, QIcon(":/resource/" + icon_fruit[index % 7]));

    return index;
}

void MainWindow::deleteTab(int index)
{
    QWidget *widget = ui->tabWidget->widget(index);
    ui->tabWidget->removeTab(index);
    delete widget;
    if (ui->tabWidget->count() <= 1) {
        ui->tabWidget->setTabsClosable(false);
    }
}

void MainWindow::setButtonOpen(bool open)
{

}

void MainWindow::on_newTab_triggered()
{
    int index = newTab();
    qDebug() << "index: " << index;
    PageInfo pi;
    pInfo << pi;
    ui->tabWidget->setCurrentIndex(index);
}

void MainWindow::on_show_Tool_Bar_toggled(bool arg1)
{
    if (arg1) {
        ui->toolBar->show();
        ui->show_Tool_Bar->setText(tr("显示Tool Bar"));
    } else {
        ui->toolBar->hide();
        ui->show_Tool_Bar->setText(tr("隐藏Tool Bar"));
    }
}

void MainWindow::on_tabWidget_tabCloseRequested(int index)
{
    qsc.close(pInfo[index].name);
    delete pInfo[index].fLog;
    pInfo.removeAt(index);
    deleteTab(index);
    refreshTabIcon();
}

void MainWindow::saveUiConfig()
{
    QFile file(uiConfName);
    file.open(QIODevice::ReadOnly | QIODevice::Text);
    QString jstr = file.readAll();
    file.close();

    QJsonObject root;
    QJsonParseError parseJsonErr;
    QJsonDocument document = QJsonDocument::fromJson(jstr.toUtf8(), &parseJsonErr);
    if (!(parseJsonErr.error == QJsonParseError::NoError)) {
        qCritical() << tr("解析配置错误：") << parseJsonErr.error;
    }
    root = document.object();
    QJsonArray pInfoJson;
    if (pInfo.size() > 0) {
        for (auto &pi : pInfo) {
            QJsonObject pInfoObj;
            pInfoObj["name"]          = pi.name;
            pInfoObj["echo"]          = pi.echo;
            pInfoObj["recStop"]       = pi.recStop;
            pInfoObj["showTimestamp"] = pi.showTimestamp;
            pInfoObj["endChar"]       = pi.endChar;
            pInfoObj["recCached"]     = pi.recCached;
            pInfoObj["linuxMode"]     = pi.linuxMode;

            QJsonObject portConfObj;
            portConfObj["baudRate"] = pi.pc.baudRate;
            portConfObj["dataBits"] = pi.pc.dataBits;
            portConfObj["flowCtrl"] = pi.pc.flowCtrl;
            portConfObj["parity"]   = pi.pc.parity;
            portConfObj["stopBits"] = pi.pc.stopBits;
            pInfoObj["portConfig"]  = portConfObj;

            QJsonArray sendRecsArray;
            for (auto &str : pi.sendRecords) {
                sendRecsArray << str;
            }
            pInfoObj["sendRecords"] = sendRecsArray;

            pInfoJson << pInfoObj;
        }
        root["pInfo"] = pInfoJson;
    }

    QJsonObject settingsWindowObj;
    QJsonObject globalSettingsObj;
    globalSettingsObj["enableToFile"] = globalSettings.log.enableToFile;
    globalSettingsObj["path"] = globalSettings.log.path;
    globalSettingsObj["maxSize"] = globalSettings.log.maxSize;
    globalSettingsObj["enableTimeshift"] = globalSettings.log.enableTimeshift;
    globalSettingsObj["overwrite"] = globalSettings.log.overwrite;
    settingsWindowObj["log"] = globalSettingsObj;
    root["globalSettings"] = settingsWindowObj;

    if (!file.open(QIODevice::WriteOnly)) {
        qCritical() << "open " << uiConfName << " file failed";
        return;
    }

    QJsonDocument jsonDoc;
    jsonDoc.setObject(root);
    file.write(jsonDoc.toJson());
//    qDebug() << jsonDoc.toJson().toStdString().c_str();
    file.close();
    qInfo() << "save config file json file success";
}

void MainWindow::readUiConfig()
{
    QFile fUiConf(uiConfName);
    if (!fUiConf.exists()) {
        qWarning() << "file " << uiConfName << " doesn't exist";
        return;
    }
    fUiConf.open(QIODevice::ReadOnly);
    QString jstr = fUiConf.readAll();
    fUiConf.close();

    QJsonObject root;
    QJsonParseError parseJsonErr;
    QJsonDocument document = QJsonDocument::fromJson(jstr.toUtf8(), &parseJsonErr);
    if (!(parseJsonErr.error == QJsonParseError::NoError)) {
        qCritical() << tr("解析配置错误：") << parseJsonErr.error;
        return;
    }

    root = document.object();
    QJsonArray pInfoJson;
    pInfoJson = root["pInfo"].toArray();
    int size = pInfoJson.size();
    if (size > 0) {
        pInfo.clear();
        for (int i = 0; i < size; i++) {
            QJsonObject pInfoObj = pInfoJson.at(i).toObject();
            PageInfo pi;
            pi.name          = pInfoObj["name"].toString();
            pi.echo          = pInfoObj["echo"].toBool();
            pi.recStop       = pInfoObj["recStop"].toBool();
            pi.showTimestamp = pInfoObj["showTimestamp"].toBool();
            pi.endChar       = pInfoObj["endChar"].toString();
            pi.recCached     = pInfoObj["recCached"].toBool();
            pi.linuxMode     = pInfoObj["linuxMode"].toBool();

            QJsonObject portConfObj = pInfoObj["portConfig"].toObject();
            pi.pc.baudRate          = (qscom::BaudRate)portConfObj["baudRate"].toInt();
            pi.pc.dataBits          = (qscom::DataBits)portConfObj["dataBits"].toInt();
            pi.pc.flowCtrl          = (qscom::FlowControl)portConfObj["flowCtrl"].toInt();
            pi.pc.parity            = (qscom::Parity)portConfObj["parity"].toInt();
            pi.pc.stopBits          = (qscom::StopBits)portConfObj["stopBits"].toInt();

            QJsonArray sendRecsAry = pInfoObj["sendRecords"].toArray();
            for (auto item : sendRecsAry) {
                pi.sendRecords << item.toString();
            }

            qDebug() << "append pInfo, pInfo size: " << pInfo.size();
            pInfo << pi;
        }
    }

    QJsonObject globalSettingsObj;
    globalSettingsObj = root["globalSettings"].toObject();
    if (!globalSettingsObj.isEmpty()) {
        QJsonObject logObj;
        logObj = globalSettingsObj["log"].toObject();
        if (!logObj.isEmpty()) {
            globalSettings.log.enableToFile = logObj["enableToFile"].toBool();
            globalSettings.log.enableTimeshift = logObj["enableTimeshift"].toBool();
            globalSettings.log.maxSize = logObj["maxSize"].toInt();
            globalSettings.log.overwrite = logObj["overwrite"].toBool();
            globalSettings.log.path = logObj["path"].toString();
        }
    }

    qDebug() << "reada ui page info size: " << pInfo.size();
}

void MainWindow::saveUiWindow()
{
    settings.setValue("mainwindow", saveState());
    settings.setValue("geometry", saveGeometry());
    settings.setValue("splitterSize", ui->splitter->saveState());
    settings.setValue("splitterSize2", ui->splitter_2->saveState());
}

int MainWindow::restoreUiWindow()
{
    restoreGeometry(settings.value("geometry").toByteArray());
    restoreState(settings.value("mainwindow").toByteArray());
    ui->splitter->restoreState(settings.value("splitterSize").toByteArray());
    ui->splitter_2->restoreState(settings.value("splitterSize2").toByteArray());
    return 0;
}

void MainWindow::closeEvent(QCloseEvent *event)
{
    qDebug() << "window close";
    saveUiConfig();
    saveUiWindow();

    QWidget::closeEvent(event);
}

//void MainWindow::keyPressEvent(QKeyEvent *event)
//{
//    if (event->type() == QEvent::KeyPress) {
//        if (event->key() == Qt::Key_Return && (event->modifiers() & Qt::ControlModifier)) {
//            qDebug() << "key press";
//        }
//    }

//    QWidget::keyPressEvent(event);
//}

bool MainWindow::eventFilter(QObject *target, QEvent *event)
{
    if (target == ui->textEdit_sendBuf) {
        QKeyEvent *key = static_cast<QKeyEvent *>(event);
        if (event->type() == QEvent::KeyPress) {
            if (key->key() == Qt::Key_Return && (key->modifiers() & Qt::ControlModifier)) {
                ui->textEdit_sendBuf->insertPlainText("\n");
                return true;
            }
            else if (key->key() == Qt::Key_Return) {
                ui->pushButton_sendData->click();
                return true;
            }
            else if (key->key() == Qt::Key_Up) {
                int count = ui->listWidget_sendRecords->count();
                if (count <= 0) {
                    return true;
                }
                int curIndex = ui->listWidget_sendRecords->currentRow();
                if (isSendRecordSelect == true && curIndex <= 0) {
                    return true;
                }
                if (isSendRecordSelect == false) {
                    isSendRecordSelect = true;
                    ui->listWidget_sendRecords->setCurrentRow(count - 1);
                    ui->textEdit_sendBuf->setText(ui->listWidget_sendRecords->currentItem()->text());
                    ui->textEdit_sendBuf->moveCursor(QTextCursor::End);
                    return true;
                }
                ui->listWidget_sendRecords->setCurrentRow(curIndex - 1);
                ui->textEdit_sendBuf->setText(ui->listWidget_sendRecords->currentItem()->text());
                ui->textEdit_sendBuf->moveCursor(QTextCursor::End);
                return true;
            }
            else if (key->key() == Qt::Key_Down) {
                if (isSendRecordSelect == false) {
                    return true;
                }
                int count = ui->listWidget_sendRecords->count();
                if (ui->listWidget_sendRecords->currentRow() >= count - 1) {
                    isSendRecordSelect = false;
                    ui->listWidget_sendRecords->setCurrentRow(-1);
                    ui->textEdit_sendBuf->clear();
                    return true;
                }
                int curIndex = ui->listWidget_sendRecords->currentRow();
                ui->listWidget_sendRecords->setCurrentRow(curIndex + 1);
                ui->textEdit_sendBuf->setText(ui->listWidget_sendRecords->currentItem()->text());
                ui->textEdit_sendBuf->moveCursor(QTextCursor::End);
                return true;
            }
        }
    }
    return QWidget::eventFilter(target, event);
}

void MainWindow::on_tabWidget_currentChanged(int index)
{
    qDebug() << "select tabWidget index: " << index;
    ui->tabWidget->setTabIcon(index, QIcon(":/resource/" + icon_fruit[index % 7]));
    setPageInfo(index);
    statusBarSetPortInfo();
}

void MainWindow::on_save_triggered()
{
    qInfo() << "save page info";
    getPageInfo(ui->tabWidget->currentIndex());
}

void MainWindow::on_refresh_triggered()
{
    spsInfo = qsc.reflush();
    ui->comboBox_port->clear();
    for (auto &spi : spsInfo) {
/* 移除不显示的串口 */
#ifdef Q_OS_WIN
        if (spi.description().contains("蓝牙链接上的标准串行")) {
#elif defined(Q_OS_LINUX)
        if (spi.portName().contains("ttyS4")) {
#endif
            continue;
        }
        ui->comboBox_port->addItem(spi.portName() + " (" + spi.description() + ")");
    }
#ifdef Q_OS_WIN
    resetComboBoxWidth(ui->comboBox_port);
#endif
    portValid();

    statusBarSetPortInfo();
}

/**
 * @brief MainWindow::portValid
 * @details 刷新所有串口时，对已经打开的串口进行检测，不存在后，就关闭该串口
 */
void MainWindow::portValid()
{
    /* 当tab不存在或者pInfo不存在时，不做检测 */
    int sizeTab = ui->tabWidget->count();
    int pSize = pInfo.size();
    if (sizeTab <= 0 || pSize <= 0) {
        return ;
    }

    int i = 0;
    for (; i < sizeTab; i++) {
        int index = getPortIndex(pInfo[i].name);
        if (index < 0) {
            qsc.close(pInfo[i].name);
            pInfo[i].open = false;
            ui->tabWidget->setTabText(i, "new");
        }
    }
    /* 设置当前tabWidget的串口状态图标 */
    int indexTab = ui->tabWidget->currentIndex();
    int index = getPortIndex(pInfo[indexTab].name);
    if (index < 0) {
        ui->openPort->setChecked(false);
        clockUi(false);
    } else {
        ui->comboBox_port->setCurrentIndex(index);
    }
}

QString MainWindow::getPortName(int index)
{
    QString str = ui->comboBox_port->itemText(index);
    QStringList sl = str.split(" ");
    if (sl.size() >= 1) {
        return sl[0];
    }
    return "";
}

int MainWindow::getPortIndex(const QString &name)
{
    int size = ui->comboBox_port->count();
    for (int i = 0; i < size; i++) {
        QString str = ui->comboBox_port->itemText(i);
        if (str.contains(name)) {
            return i;
        }
    }
    return -1;
}

void MainWindow::clockUi(bool clock)
{
    ui->comboBox_baudRate->setEnabled(!clock);
    ui->comboBox_dataBits->setEnabled(!clock);
    ui->comboBox_flowCtrl->setEnabled(!clock);
    ui->comboBox_parity->setEnabled(!clock);
    ui->comboBox_stopBits->setEnabled(!clock);
    ui->comboBox_port->setEnabled(!clock);
}

void MainWindow::on_openPort_triggered(bool checked)
{
    int index = ui->tabWidget->currentIndex();
    if (checked) {
        getPageInfo(index);
        if (qsc.open(pInfo[index].name, pInfo[index].pc) != qscoms::SUCCESS) {
            QMessageBox::StandardButton btn = (QMessageBox::StandardButton )QMessageBox::critical(this, tr("错误！"), tr("打开串口失败，请检查串口是否存在或者被占用"), tr("确认"), tr("退出"));
            (void )btn;
            ui->openPort->setChecked(false);
            return ;
        }
        /* 打开串口成功 */
        qsc.setCached(pInfo[index].name, ui->linuxMode->isChecked());
        pInfo[index].open = true;
        ui->tabWidget->setTabText(index, pInfo[index].name);
//        ui->tabWidget->setTabText(index, ui->comboBox_port->itemText(getPortIndex(pInfo[index].name))); /* tab widget显示串口全称 */
        clockUi(true);
        /* 设置日志保存 */
        pInfo[index].fLog = new FileLog(pInfo[index].name, QDir(globalSettings.log.path),globalSettings.log.maxSize,
                                            globalSettings.log.enableTimeshift, globalSettings.log.overwrite);
        pInfo[index].fLog->logEnable(globalSettings.log.enableToFile);
    } else {
        qsc.close(pInfo[index].name);
        pInfo[index].open = false;
        ui->tabWidget->setTabText(index, "new");
        clockUi(false);
    }

    statusBarSetPortInfo();
}

MainWindow::PageInfo * MainWindow::getPageInfo(const QString &name)
{
    for (auto &pi : pInfo) {
        if (pi.name == name) {
            return &pi;
        }
    }
    return nullptr;
}

void MainWindow::on_pushButton_sendData_clicked()
{
    QString data = ui->textEdit_sendBuf->toPlainText();
    QString name = getPortName(ui->comboBox_port->currentIndex());
    if (!qsc.isOpen(name)) {
        qDebug() << "serial port isn't opened, data send failed";
        return ;
    }

    /* 缓存发送记录 */
    addSendRecord(ui->tabWidget->currentIndex(), data);

    /* 添加结束符 */
    if (ui->comboBox_endChar->currentText() != "NULL") {
        data += endChar[ui->comboBox_endChar->currentIndex()];
    }

    /* 数据回显 */
    if (ui->checkBox_echo->isChecked()) {
        QString echoData = data;
        /* 添加时间戳 */
        if (ui->checkBox_showTime->isChecked()) {
            QDateTime timestamp = QDateTime::currentDateTime();
            echoData = timestamp.toString("[yyyy-MM-dd hh:mm:ss]<< ") + echoData;
            /* 对没有换行的数据进行换行 */
            int pos = echoData.length();
            if (pos - 1 >= 0 && pos - 2 >= 0 && echoData.at(pos - 1) == '\r') {
                if (echoData.at(pos - 2) != '\n') {
                    echoData += "\n";
                } else {
                    echoData.remove(pos - 1, 1);
                }
            } else if (echoData.at(pos - 1) != '\n') {
                echoData += "\n";
            }
        }
        dataRecWidgetAppend(ui->tabWidget->currentIndex(), echoData);
    }

    qDebug() << "send data: " << data;
    /* 串口发送 */
    if (qsc.send(name, data) != qscoms::SUCCESS) {
        qDebug() << "serial port send data failed";
        return ;
    }

    PageInfo * pi = getPageInfo(name);
    pi->fLog->logSave(data);

    /* 清除缓冲区 */
    ui->textEdit_sendBuf->clear();
}

void MainWindow::stopRec(bool stop)
{
    int index = ui->tabWidget->currentIndex();
    pInfo[index].recStop = stop;
}

void MainWindow::on_radioButton_rec_clicked(bool checked)
{
    stopRec(!checked);
    ui->noReceive->setChecked(!checked);
}

void MainWindow::on_noReceive_triggered(bool checked)
{
    stopRec(checked);
    ui->radioButton_rec->setChecked(!checked);
}

void MainWindow::on_newSession_triggered()
{
    on_newTab_triggered();
}

void MainWindow::on_save_2_triggered()
{
    on_save_triggered();
}

void MainWindow::on_saveAll_triggered()
{
    getPageInfo(ui->tabWidget->currentIndex());
    saveUiConfig();
    qDebug() << "save all";
}

void MainWindow::on_eraseTextEdit_triggered()
{
    QPlainTextEdit *pte = (QPlainTextEdit *)ui->tabWidget->currentWidget();
    pte->clear();
}

void MainWindow::on_showSettingsWin_triggered(bool checked)
{
    ui->widget_settingsWin->setHidden(!checked);
}


void MainWindow::on_tabPre_triggered()
{
    int index = ui->tabWidget->currentIndex();
    ui->tabWidget->setCurrentIndex(index - 1);
}


void MainWindow::on_tabNext_triggered()
{
    int index = ui->tabWidget->currentIndex();
    ui->tabWidget->setCurrentIndex(index + 1);
}


void MainWindow::on_closeSession_triggered()
{
    int tabSize = ui->tabWidget->count();
    if (tabSize <= 1) {
        return;
    }
    int index = ui->tabWidget->currentIndex();
    qsc.close(pInfo[index].name);
    delete pInfo[index].fLog;
    pInfo.removeAt(index);
    deleteTab(index);
    refreshTabIcon();
}

void MainWindow::refreshTabIcon()
{
    int sizeTab = ui->tabWidget->count();
    for (int i = 0; i < sizeTab; i++) {
        ui->tabWidget->setTabIcon(i, QIcon(":/resource/" + icon_fruit[i % 7]));
    }
}


void MainWindow::on_linuxMode_triggered(bool checked)
{
    if (ui->tabWidget->count() <= 0) {
        return ;
    }
    int index = ui->tabWidget->currentIndex();
    pInfo[index].linuxMode = checked;
    if (checked) {
        ui->checkBox_echo->setChecked(!checked);
        ui->checkBox_showTime->setChecked(!checked);
        ui->recCached->setChecked(!checked);
        ui->comboBox_endChar->setCurrentText("\\n");
        qsc.setCached(pInfo[index].name, false);
        getPageInfo(ui->tabWidget->currentIndex());
    }
    ui->checkBox_echo->setEnabled(!checked);
    ui->checkBox_showTime->setEnabled(!checked);
    ui->comboBox_endChar->setEnabled(!checked);
    ui->recCached->setEnabled(!checked);
}

void MainWindow::on_recCached_triggered(bool checked)
{
    int index = ui->tabWidget->currentIndex();
    qsc.setCached(pInfo[index].name, checked);
}

void MainWindow::on_comboBox_endChar_currentIndexChanged(int index)
{
    (void)index;
    /* 界面初始化时，数据还未准备好，则不进行保存，否则会QList越界 */
    if (ui->tabWidget->count() <= 0 || pInfo.size() <= 0 || ui->tabWidget->count() < pInfo.size()) {
        return ;
    }
    int index1 = ui->tabWidget->currentIndex();
    getPageInfo(index1);
}

void MainWindow::on_checkBox_echo_clicked(bool checked)
{
    (void)checked;
    int index = ui->tabWidget->currentIndex();
    getPageInfo(index);
}

void MainWindow::on_checkBox_showTime_clicked(bool checked)
{
    (void)checked;
    int index = ui->tabWidget->currentIndex();
    getPageInfo(index);
}

void MainWindow::addSendRecord(int index, const QString &data)
{
    if (data == "") {
        return ;
    }
    /* 在选中某一项记录时，如果对记录进行修改后再发送，会导致该item会一直有被选中的效果，因此在添加记录时，选取消所有选择的item*/
    ui->listWidget_sendRecords->setCurrentRow(-1);

    QStringList &srlist = pInfo[index].sendRecords;
    int pos = srlist.indexOf(data);
    if (pos >= 0) {
        srlist.removeAt(pos);
        QListWidgetItem *item = ui->listWidget_sendRecords->takeItem(pos);
        ui->listWidget_sendRecords->removeItemWidget(item);
        delete item;
    }

    ui->listWidget_sendRecords->addItem(data);
    srlist << data;

    int size = ui->listWidget_sendRecords->count();
    if (size > RECORD_LIST_MAX_SZE) {
        QListWidgetItem *item = ui->listWidget_sendRecords->takeItem(0);
        ui->listWidget_sendRecords->removeItemWidget(item);
        delete item;
        srlist.removeAt(0);
    }
    isSendRecordSelect = false;
}

/**
 * @brief MainWindow::on_listWidget_sendRecords_customContextMenuRequested
 * @details 添加右键菜单删除选项，需要设置contextMenuPolicy属性为CustomContextMenu
 * @param pos
 */
void MainWindow::on_listWidget_sendRecords_customContextMenuRequested(const QPoint &pos)
{
    QListWidgetItem *item = ui->listWidget_sendRecords->itemAt(pos);
    if (item == NULL) return;

    QMenu *popMenu = new QMenu(this);
    QAction *deleteSeed = new QAction(tr("Delete"), this);
    popMenu->addAction(deleteSeed);
    connect(deleteSeed, SIGNAL(triggered()), this, SLOT(deleteSeedSlot()));
    popMenu->exec(QCursor::pos());
    delete popMenu;
    delete deleteSeed;
}

void MainWindow::deleteSeedSlot()
{
    QList<QListWidgetItem*> list = ui->listWidget_sendRecords->selectedItems();
    if(list.size() == 0) return;
    foreach (QListWidgetItem* var, list)
    {
        int r = ui->listWidget_sendRecords->row(var);
        ui->listWidget_sendRecords->takeItem(r);
        delete var;
    }
}

/**
 *  @details windows下的USB热插拔监听方式
 */
#ifndef LINUX_USB_MONITOR_MOD
bool MainWindow::nativeEventFilter(const QByteArray & eventType, void * message, long * result)
{
    MSG* msg = reinterpret_cast<MSG*>(message);
    int msgType = msg->message;
    if (msgType == WM_DEVICECHANGE) {
        PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)msg->lParam;
        switch (msg->wParam) {
        case DBT_DEVICEARRIVAL:
            if (lpdb->dbch_devicetype == DBT_DEVTYP_PORT) {
                PDEV_BROADCAST_PORT lpdbv = (PDEV_BROADCAST_PORT)lpdb;
                QString port = QString::fromWCharArray(lpdbv->dbcp_name);//插入的串口名
                qDebug() << "USB insert: " << port;
                on_refresh_triggered();
            }
            break;
        case DBT_DEVICEREMOVECOMPLETE:
            if (lpdb->dbch_devicetype == DBT_DEVTYP_PORT) {
                PDEV_BROADCAST_PORT lpdbv = (PDEV_BROADCAST_PORT)lpdb;
                QString port = QString::fromWCharArray(lpdbv->dbcp_name);//拔出的串口名
                qDebug() << "USB pull out: " << port;
                on_refresh_triggered();
            }
            break;
        case DBT_DEVNODES_CHANGED:
            break;
        default:
            break;
        }
    }
    return QWidget::nativeEvent(eventType, message, result);
}
#endif

/**
 * @brief MainWindow::resetComboBoxWidth
 * @detail 设置combox的宽度显示效果，windows下，解决combox每一项显示不全的问题
 * @param cb
 */
void MainWindow::resetComboBoxWidth(QComboBox *cb)
{
    int maxLen = 0;
    for (int i = 0; i < cb->count(); i++) {
        if (maxLen < cb->itemText(i).length()) {
            maxLen = cb->itemText(i).length();
        }
    }
    int pt_val = cb->font().pointSize();
    cb->view()->setFixedWidth(maxLen * pt_val * 1.5);
}

void MainWindow::statusBarInit()
{
    labelPortStatusIco = new QLabel(this);
    labelPortName = new QLabel(this);

    statusBar()->addWidget(labelPortStatusIco);
    statusBar()->addWidget(labelPortName);

    labelPortStatusIco->setMaximumSize(16,16);

    labelPortName->setScaledContents(true);
    labelPortStatusIco->setScaledContents(true);

    labelPortName->setAlignment(Qt::AlignCenter);
    labelPortStatusIco->setAlignment(Qt::AlignCenter);

    statusBarSetPortInfo(false, "no ports selected");
}

void MainWindow::statusBarSetPortInfo(bool connected, const QString &portInfo)
{
    if (!labelPortStatusIco || !labelPortName) return ;
    labelPortName->setText(portInfo);

    QPixmap *connectedIcon;
    if (connected) {
        connectedIcon = new QPixmap(":/resource/yes.png");
    } else {
        connectedIcon = new QPixmap(":/resource/no.png");
    }
    labelPortStatusIco->setPixmap(*connectedIcon);
}

void MainWindow::statusBarSetPortInfo()
{
    if (!labelPortStatusIco || !labelPortName) return ;
    QString portName = getPortName(ui->comboBox_port->currentIndex());
    if ( portName == "" || getPortIndex(portName) < 0) {
        statusBarSetPortInfo(false, "No ports selected");
        return ;
    }
    bool connected = qsc.isOpen(portName);
    QString info;
    info = ui->comboBox_port->currentText() + (connected ? " Opened" : " Closed");
    statusBarSetPortInfo(connected, info);
}

void MainWindow::on_comboBox_port_currentIndexChanged(int index)
{
    (void )index;
    statusBarSetPortInfo();
}


void MainWindow::on_listWidget_sendRecords_itemClicked(QListWidgetItem *item)
{
    isSendRecordSelect = true;
    ui->textEdit_sendBuf->setText(item->text());
    ui->textEdit_sendBuf->moveCursor(QTextCursor::End);
    ui->textEdit_sendBuf->setFocus();
}


void MainWindow::on_action_sendList_triggered(bool checked)
{

}


void MainWindow::on_action_settingsWindow_triggered()
{
    settingsWin = new SettingsWindow(globalSettings);

    connect(settingsWin, &SettingsWindow::sigSettingsValid, this, &MainWindow::slotSettingsValid);

    settingsWin->show();
}

void MainWindow::slotSettingsValid(SettingsWindow::settingsWindow &sw)
{
    qDebug() << __FUNCTION__ << "  Settings valid";
    for ( auto &pi : pInfo) {
        if (pi.fLog) {
            pi.fLog->logEnable(sw.log.enableToFile);
        }
    }
    ui->action_logToFile->setChecked(sw.log.enableToFile);
}


void MainWindow::on_action_logToFile_triggered(bool checked)
{
    globalSettings.log.enableToFile = checked;
    for ( auto &pi : pInfo) {
        if (pi.fLog) {
            pi.fLog->logEnable(checked);
        }
    }
}

